using System;
using System.IO;
using System.Text;

namespace Magic.Core
{
	/// <summary>
	/// Reads primitive data types using a specified byte order.
	/// </summary>
	public class EndianReader : BinaryReader
	{
		private ByteOrder	order;

		public EndianReader(Stream inStream, ByteOrder bOrder, Encoding tEncoding) : base(inStream, tEncoding)
		{
			order = bOrder;
		}

		public EndianReader(Stream inStream, ByteOrder bOrder) : base(inStream, Encoding.ASCII)
		{
			order = bOrder;
		}

		public virtual Int24 ReadInt24()
		{
			return new Int24(EndianSwap.SwapToInt32(base.ReadBytes(4),order));
		}

		public virtual Int24 ReadInt24(int magic)
		{
            Int24 int24 = new Int24(EndianSwap.SwapToInt32(base.ReadBytes(4),order));
			int24.Integer += magic;
			return int24;
		}

		public override short ReadInt16()
		{
            return EndianSwap.SwapToInt16(base.ReadBytes(2), order);
		}
        public short[] ReadInt16Array(int count)
        {
            short[] temp = new short[count];
            for (int i = 0; i < count; i++)
            {
                temp[i] = EndianSwap.SwapToInt16(base.ReadBytes(2), order);
            }
            return temp;
        }
        public override int ReadInt32()
        {
            return EndianSwap.SwapToInt32(base.ReadBytes(4),order);
        }
        public int[] ReadInt32Array(int count)
        {
            int[] temp = new int[count];
            for (int i = 0; i < count; i++)
            {
                temp[i] = EndianSwap.SwapToInt32(base.ReadBytes(4),order);
            }
            return temp;
        }

		public override long ReadInt64()
		{
            return EndianSwap.SwapToInt64(base.ReadBytes(8), order);
		}

		public override ushort ReadUInt16()
		{
			return BitConverter.ToUInt16(ByteSwap(BitConverter.GetBytes(base.ReadUInt16())), 0);
		}

		public override uint ReadUInt32()
		{
			return BitConverter.ToUInt32(ByteSwap(BitConverter.GetBytes(base.ReadUInt32())), 0);
		}

		public override ulong ReadUInt64()
		{
			return BitConverter.ToUInt64(ByteSwap(BitConverter.GetBytes(base.ReadUInt64())), 0);
		}

		public override float ReadSingle()
		{
            return EndianSwap.SwapToSingle(base.ReadBytes(4), order);
			//return BitConverter.ToSingle(ByteSwap(BitConverter.GetBytes(base.ReadSingle())), 0);
		}
        public float[] ReadSingleArray(int count)
        {
            float[] temp = new float[count];
            for (int i = 0; i < count; i++)
            {
                temp[i] = EndianSwap.SwapToSingle(base.ReadBytes(4), order); //BitConverter.ToSingle(ByteSwap(BitConverter.GetBytes(base.ReadSingle())), 0);
            }
            return temp;
        }
		public override double ReadDouble()
		{
			return BitConverter.ToDouble(ByteSwap(BitConverter.GetBytes(base.ReadDouble())), 0);
		}

		public virtual string ReadFourCC()
		{
			string fourcc = ReadString(4);
			if(order == ByteOrder.LittleEndian)
				return EndianSwap.ReverseString(fourcc);
			else
				return fourcc;
		}

		public virtual int Position
		{
			get {return (int)base.BaseStream.Position;}
			set {base.BaseStream.Position = value;}
		}

		public virtual int Length
		{
			get {return (int)base.BaseStream.Length;}
			set {base.BaseStream.SetLength(value);}
		}

        public virtual string ReadString(int len)
        {
            return System.Text.ASCIIEncoding.ASCII.GetString(base.ReadBytes(len));
        }
        public virtual string ReadString(int len,bool nullend = false)
        {
            string ret = System.Text.ASCIIEncoding.ASCII.GetString(base.ReadBytes(len));
            if (nullend)
                base.ReadByte();
            return ret;
        }

		public virtual string ReadString(Int24 stats)
		{
			long pos = base.BaseStream.Position;
			base.BaseStream.Position = stats.Integer;
			string str = String.Empty;
			for(byte x = 0; x < stats.Byte; x++)
				str += Convert.ToChar(base.ReadByte());
			base.BaseStream.Position = pos;
			return str;
		}

		public override string ReadString()
		{
			char chr = '\0';
			string str = "";
			do
			{
				chr = Convert.ToChar(base.ReadByte());
				str += chr;
			} while (chr != '\0');
			return str.Substring(0,str.Length-1);
		}


		protected byte[] ByteSwap(byte[] bytes)
		{
			if(order == ByteOrder.BigEndian)
			{
				switch (bytes.Length)
				{
					case 2:
					case 4:
					case 8:
						EndianSwap.ByteSwap(bytes);
						break;
					default:
						throw new NotSupportedException("Stream lengths other than 2, 4, and 8 are invalid for an endian swap.");
				}
			}
			return bytes;
		}
	}
}
